On this page
일본어 폰트·타이포그래피 - 한국인 웹 개발자가 자주 놓치는 것들
On this page
- 일본인 신규 입사자가 일본어 페이지 보고 피드백 줌
- "쉼표나 장음부호 앞뒤 공백이 이상하다"
企画、制作에서、오른쪽이 비어 보여서 스페이스 문자 낀 줄 알았음- DOM 까보니 스페이스 없음
- 한글 서비스만 만들 땐 마주칠 일 없던 문제라 정리해둠
、와 ー는 각각 별도의 유니코드 문자
、= U+3001 IDEOGRAPHIC COMMAー= U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK- 둘 다 ASCII
,,-와 다른 문자 - 폰트 안에서 별도 glyph·metrics 가짐
- 둘 다 ASCII
- 전각 문장부호는 glyph 자체에 내부 여백(side bearing/advance) 있음
- 눈으로 봤을 때 공백처럼 보여도 실제 스페이스 문자 있는 건 아님
한국어 서비스 습관을 일본어에 그대로 가져가면 어긋나는 지점:
- 단어 사이에 공백이 있다는 전제
- → 일본어는 일반 문장에 띄어쓰기가 거의 없음
- → 줄바꿈 기회가 문자 사이에 존재
word-break: keep-all을 자주 씀- → 일본어 본문에 적용하면 정상적인 CJK 줄바꿈을 막아서 overflow 생김
- 쉼표
,기준으로 생각- →
、는 전각 문장부호라 글리프 폭·여백 모델이 다름
- →
- 하이픈/대시와 비슷한 선으로 인식
- →
ー는 가타카나·히라가나 장음부호로 완전히 다른 문자
- →
용어 정리 (한국어 이름으로 기억하고, 괄호 안 한자·발음은 검색 키워드로):
- 문장부호·기호류 (
約物, やくもの, yakumono)- 일본어 조판에서 별도 간격 규칙이 붙는 문장부호·기호류
- 조판 규칙 (
文字組み, もじぐみ)- 글자 배치·간격·줄바꿈을 아우르는 조판 규칙 전반
- 금칙 처리 (
禁則処理, きんそくしょり, kinsoku shori)- 문장부호가 줄 맨 앞/뒤에 부자연스럽게 오는 걸 막는 규칙
- 전각/반각 (
全角/半角)A와A처럼 폭이 다른 문자 형태- 검색·정규화·UI 폭 계산에 영향
lang="ja"
- 페이지가 일본어면 문서 루트에
lang="ja" - 일부 영역만 일본어면 해당 영역에 지정
- 접근성·음성합성뿐 아니라
:lang(ja)셀렉터로 일본어 전용 스타일 스코프하는 기준이 됨
<html lang="ja">...</html><!-- 다국어 페이지 일부만 일본어 --><p>한국어 설명<span lang="ja">ショート動画広告の企画、制作</span></p>
- 후리가나 필요하면 이미지나 JS로 만들지 말고
<ruby>태그 사용
<ruby lang="ja">日本語<rt>にほんご</rt></ruby>
- locale이 일본어인데 루트
lang이 계속ko로 남아있는 경우 실무에서 은근히 있음- 이것부터 먼저 고칠 것
font-family에 적었다고 그 폰트가 그렸다는 뜻은 아님
:lang(ja) {font-family:"Hiragino Sans","Yu Gothic","YuGothic","Meiryo","Noto Sans JP",sans-serif;}
- 가장 중요한 확인 포인트는 glyph fallback
- 지정한 폰트가 일본어 글리프를 포함 안 하거나 웹폰트 subset에서 빠지면, 브라우저가 그 문자만 다른 폰트로 대체함
ー,、, 괄호 같은 기호만 다른 metrics 가진 폰트로 떨어지면 그 부분만 이질감 생김- Chrome DevTools → Elements → Computed → Rendered Fonts 에서 문제되는 노드 직접 확인하는 게 제일 빠름
- 웹폰트 subset 만들 때 흔한 실수
- 가나·한자만 남기고 문장부호를 빠뜨림
- → punctuation만 system fallback으로 튀어서 폰트 안 맞아 보임
- 폰트 로딩 타이밍도 줄바꿈에 영향
- 일본어는 문자 단위 줄바꿈이 많아서 fallback font와 최종 font의 advance width 차이가 한 줄의 마지막 문자 위치를 바꿀 수 있음
font-display: swap쓴다면 CLS뿐 아니라 "첫 렌더와 로딩 후 줄바꿈이 달라지는가"도 볼 것
word-break: keep-all을 일본어에 그대로 쓰면 안 됨
- 일본어는 공백 없이 문장이 이어져서 브라우저가 문자 사이의 줄바꿈 기회를 판단
- 여기에 금칙처리 규칙까지 겹침
、。)]」』같은 닫는 문장부호가 줄 맨 앞에 오는 것 피함([「『같은 여는 문장부호가 줄 맨 끝에 오는 것 피함
:lang(ja) {line-break: strict;word-break: normal;overflow-wrap: break-word; /* 긴 URL/식별자 같은 예외 대응 */}
- 한국어 CSS 복사하면서 가장 자주 하는 실수 —
word-break: keep-all을 일본어에도 같이 적용- 일본어의 정상적인 CJK 줄바꿈 기회를 지나치게 없애버려서 컨테이너 폭 넘어가는 문제 생김
같은 문장을 폭 260px 박스에 넣고 비교하면 차이가 바로 보임.
word-break: normal
ショート動画広告の企画、制作という講座では、企画から編集まで一連の流れを学びます。
word-break: keep-all
ショート動画広告の企画、制作という講座では、企画から編集まで一連の流れを学びます。
keep-all쪽은 문자 사이의 정상적인 줄바꿈 기회가 막혀서 박스 폭을 넘어가거나 한 단어처럼 취급된 구간이 삐져나옴
font-feature-settings: "palt"
- OpenType feature는 폰트가 제공하는 대체 glyph·metrics를 선택하는 기능
- 일본어에서 자주 마주치는 태그
palt(비례폭)pwidvert(세로쓰기용)
/* low-level: 폰트가 palt를 제공할 때만 효과가 있음 */.jp-heading {font-feature-settings: "palt" 1;}/* 가능하면 의미가 더 분명한 상위 속성을 우선 검토 */.jp-ui {font-variant-east-asian: proportional-width;}
palt를 "일본어면 무조건 켜야 하는 옵션"으로 다루면 안 됨- 폰트와 디자인 의도에 따라 결과 달라짐
- 이미
letter-spacing으로 자간 조정한 UI에 같이 걸면、。같은 문장부호 간격이 예상과 다르게 보일 수 있음 - 이 효과는 폰트가
palt테이블을 가지고 있을 때만 나타남- 시스템 폰트로 비교하면 브라우저가
palt지원 안 하는 폰트로 fallback돼서 차이가 거의 안 보일 수 있음 - 아래 예시는
palt확실히 지원하는 Noto Sans JP를 웹폰트로 강제 지정해서 비교
- 시스템 폰트로 비교하면 브라우저가
palt 없음 (Noto Sans JP)
ショート動画広告の企画、制作という講座では、
font-feature-settings: "palt" 1 (Noto Sans JP)
ショート動画広告の企画、制作という講座では、
- 같은 폰트인데도
、같은 전각 문장부호 주변 여백이 오른쪽에서 눈에 띄게 좁아짐 - 반대로 시스템 폰트에 그대로
palt만 걸면 폰트가 그 테이블을 갖고 있는지에 따라 결과 달라짐- 실제 서비스 적용 전 반드시 실 사용 폰트로 확인할 것
- 디자인 툴과 브라우저 렌더링이 다르게 보이면 비교 순서
- Figma 등에서 어떤 OpenType feature가 활성화됐는지
- 브라우저에서 동일 폰트 파일을 쓰는지
font-feature-settings,font-variant-east-asian,letter-spacing설정이 같은지
text-autospace / text-spacing-trim
text-autospace- CJK 문자와 Latin/숫자 사이의 자동 간격 제어 (2025 Baseline)
- "일본어 + 영문 제품명 + 숫자"가 섞이는 UI에서 유용
- 단, 이미 번역 문자열에 수동으로 공백을 넣어놨다면 중복 간격 생길 수 있음
@supports (text-autospace: normal) {:lang(ja) {text-autospace: normal;}}
text-spacing-trim- CJK 문장부호가 가진 내부 여백을 인접 문자나 행 시작/끝에서 다듬는 속성
- "구두점 주변이 유난히 비어 보인다"는 CS와 개념적으로 가장 가까운 속성
- 2026년 기준으로도 일부 주요 브라우저에서 지원 제한적
- polyfill 있다고 가정하지 말고 progressive enhancement로만 쓸 것
@supports (text-spacing-trim: normal) {:lang(ja) {text-spacing-trim: normal;}}
Intl.Segmenter
- 일본어 문자열을
split(' ')과length로 다루면 안 됨- 공백으로 단어가 구분되지 않기 때문
- 단어 수·검색 하이라이트·텍스트 분석은 locale-aware segmentation 사용
const segmenter = new Intl.Segmenter('ja-JP', {granularity: 'word',});const segments = [...segmenter.segment('吾輩は猫である。名前はたぬき。')];const words = segments.filter(({ isWordLike }) => isWordLike).map(({ segment }) => segment);
- "문자 수"와 UTF-16 길이도 다름
- 평범한 일본어 BMP 문자는
text.length와 겉보기 글자 수가 우연히 맞아떨어지는 경우 많음 - 이모지·결합 문자·variation selector 섞이면 어긋남
- 사용자가 눈으로 보는 글자 수 세야 한다면 grapheme 기준으로 셀 것
- 평범한 일본어 BMP 문자는
const graphemes = new Intl.Segmenter('ja-JP', {granularity: 'grapheme',});const count = [...graphemes.segment(text)].length;
- 정규화도 표시 문자열과 검색 키를 분리해야 함
NFKC는 전각 Latin/숫자, 반각 가타카나 같은 compatibility 형태를 접어서 검색 편의성 높임- 단, 원문 표기 자체를 바꿔버림
- 저장·표시용 원문은 그대로 두고, 검색용 파생 키에만 적용하는 편이 안전
const raw = input; // 표시/원본 보존const searchKey = raw.normalize('NFKC').toLocaleLowerCase('ja-JP');
- CSS로 풀 문제를 문자열에 공백 하드코딩해서 고치면 안 됨
企画、制作→企画、 制作처럼 번역 문자열에 스페이스 박아넣는 방식- 폰트가 바뀌거나
text-autospace가 활성화되는 순간 다시 깨짐 - 복사·검색 데이터에도 영향 줌
"일본어 공백이 이상하다" CS가 오면 이 순서로 봄
- 문자 확인
- 실제로
ー(U+30FC),、(U+3001)인지 - ASCII 유사문자로 변환되지 않았는지
- 실제로
- DOM whitespace 확인
- 문자열에 실제 space/NBSP가 삽입됐는지
- Rendered Fonts 확인
- 문제되는 punctuation만 fallback된 것은 아닌지
- CSS 제거 실험
letter-spacing,word-spacing,font-feature-settings를 하나씩 꺼봄
- 일본어 전용 폰트 강제
- Noto Sans JP 등 확실한 일본어 폰트로 비교
- 줄바꿈 규칙 확인
lang="ja",line-break,word-break
- 브라우저/OS 비교
- macOS Hiragino, Windows Yu Gothic/Meiryo 등 fallback 차이 분리
- 디자인 툴 비교
- 동일 폰트 파일·weight·OpenType feature가 맞는지
ー,、전후의 "공백 균형"은 실제 스페이스보다 glyph metrics + fallback + letter-spacing + OpenType 조합일 가능성을 먼저 의심하는 게 맞음
참고
- W3C - Japanese Script Resources
- 일본어 조판, 구두점, 줄바꿈, 정렬 관련 자료 허브
- W3C - Requirements for Japanese Text Layout (JLREQ)
- JIS X 4051 기반 일본어 조판 요구사항
- MDN - lang global attribute
- MDN - font-feature-settings
- MDN - word-break
- CJK 줄바꿈 값의 차이
- MDN - text-autospace
- MDN - text-spacing-trim
- 2026년 기준 제한 지원
- MDN - Intl.Segmenter
Edit this page
최근 수정 시각 9/6/2026